package com.hzb.LNReader.convertor;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;

public class HtmlToTxtConvertor implements HtmlHandler {
	
	public HtmlToTxtConvertor(File dst) throws FileNotFoundException, UnsupportedEncodingException {
		out = new FileOutputStream(dst);
	}
	
	public void finish() throws IOException {
		try {
			out.close();
		} finally {
			out = null;
		}
	}
	public FileOutputStream out = null;
	static final byte CR = (byte) '\n', IMG_CODE = (byte) '!',
			AMP = (byte) '&', AAMP = (byte) '#', EAMP = (byte) ';',
			SP = (byte) ' ';

	static final String SRC = "src";
	boolean isStart = false;
	boolean isNewline = true, isWhiteSpace = true;
	byte[] escapseChar = new byte[10];
	int escapeLen = 0;
	boolean escapsing = false;
	private String encoding = "GBK";
	
	final HashMap<String, byte[]> escapseMap = new HashMap<String, byte[]>();

	public void onEncodingChange(String encoding)
			throws UnsupportedEncodingException {
		this.encoding = encoding;

		escapseMap.put("amp", "&".getBytes(encoding));
		escapseMap.put("lt", "<".getBytes(encoding));
		escapseMap.put("gt", ">".getBytes(encoding));
		escapseMap.put("nbsp", " ".getBytes(encoding));
		escapseMap.put("ensp", "　".getBytes(encoding));
		escapseMap.put("emsp", "　".getBytes(encoding));
		escapseMap.put("quot", "\"".getBytes(encoding));
		escapseMap.put("copy", "©".getBytes(encoding));
		escapseMap.put("reg", "®".getBytes(encoding));
		escapseMap.put("trade", "™".getBytes(encoding));
		escapseMap.put("times", "×".getBytes(encoding));
		escapseMap.put("divide", "÷".getBytes(encoding));
	}

	public void characters(byte[] ch, int start, int length)
			throws Exception {
		if (ignore || !isStart)
			return;

		if (isNewline && ch[start] == IMG_CODE) {
			out.write(IMG_CODE);
			isNewline = false;
		}
		int first = start;
		int limit = start + length;
		for (int i = start;; i++) {
			if (escapsing) {
				if (ch[i] == EAMP || Character.isWhitespace(ch[i])) {
					endEscape();
					first = i + 1;
				} else {
					escapseChar[escapeLen++] = ch[i];
				}
			} else {
				if (i == limit) {
					if (!isWhiteSpace) {
						out.write(ch, first, i - first);
						isNewline = false;
					}
					break;
				}
				if (Character.isWhitespace(ch[i])) {
					if (isWhiteSpace) {
					} else {
						isWhiteSpace = true;
						if (first != i) {
							out.write(ch, first, i - first);
							first = i;
						}
						out.write(' ');
						isNewline = false;
					}
				} else {
					if (ch[i] == AMP) {
						escapsing = true;
						escapseChar[0] = AMP;
						escapeLen = 1;
						if (first != i && !isWhiteSpace) {
							out.write(ch, first, i - first);
							isNewline = false;
						}
					} else {
						if (isWhiteSpace) {
							first = i;
							isWhiteSpace = false;
						}
					}
				}
			}
		}
	}

	private void endEscape() throws IOException {
		byte[] tChar = null;
		if (escapseChar[1] == AAMP) {
			int ascii = 0;
			for (int j = 2; j < escapeLen; j++) {
				int cha = escapseChar[j] - '0';
				if (0 <= cha && cha <= 9) {
					ascii = ascii * 10 + cha;
				} else {
					ascii = 0;
					break;
				}
			}
			if (ascii > 0) {
				tChar = new byte[] { (byte) ascii };
			}
		} else {
			String str = new String(escapseChar, 1, escapeLen - 1);
			tChar = escapseMap.get(str);
		}
		escapeLen = 0;
		escapsing = false;
		if (tChar == null) {
			out.write(escapseChar, 0, escapeLen);
		} else {
			out.write(tChar);
		}
		isNewline = false;
	}

	public void endCharacters() throws Exception {
		if (escapsing)
			endEscape();
	}

	public void endElement(String localName) throws Exception {
		if (ignore) {
			if (ignoreCount == 0) {
				ignore = false;
				currIgnoreTag = null;
			} else if (currIgnoreTag.equalsIgnoreCase(localName))
				ignoreCount--;
			return;
		}

		if ("p".equalsIgnoreCase(localName)) {
			out.write(CR);
			isNewline = isWhiteSpace = true;
		} else if ("br".equalsIgnoreCase(localName)) {
			out.write(CR);
			isNewline = isWhiteSpace = true;
		} else if ("tr".equalsIgnoreCase(localName)) {
			out.write(CR);
			isNewline = isWhiteSpace = true;
		} else if ("div".equalsIgnoreCase(localName)) {
			out.write(CR);
			isNewline = isWhiteSpace = true;
		} else if ("li".equalsIgnoreCase(localName)) {
			out.write(CR);
			isNewline = isWhiteSpace = true;
		} else if ("td".equalsIgnoreCase(localName)) {
			out.write(SP);
			isWhiteSpace = true;
		} else if ("body".equalsIgnoreCase(localName)) {
			isStart = false;
		}

	}

	boolean ignore = false;
	int ignoreCount = 0;
	String currIgnoreTag;

	public void startElement(String localName,
			HashMap<String, String> attributes) throws Exception {
		if (ignore) {
			if (currIgnoreTag.equalsIgnoreCase(localName))
				ignoreCount++;
			return;
		}

		if ("img".equalsIgnoreCase(localName)) {
			ignore = true;
			String src = attributes.get(SRC);
			if (src != null) {
				out.write(IMG_CODE);
				src = URLDecoder.decode(src, "UTF-8");
				out.write(src.getBytes(encoding));
				out.write(CR);
			}
		} else if ("script".equalsIgnoreCase(localName)) {
			ignore = true;
			currIgnoreTag = "script";
		} else if ("style".equalsIgnoreCase(localName)) {
			ignore = true;
			currIgnoreTag = "style";
		} else if ("iframe".equalsIgnoreCase(localName)) {
			ignore = true;
			currIgnoreTag = "iframe";
		} else if ("body".equalsIgnoreCase(localName)) {
			isStart = true;
		}
	}
}
